#include "../exercise.h"

// READ: 枚举类型 <https://zh.cppreference.com/w/cpp/language/enum>

// `enum` 是 C 的兼容类型，本质上其对应类型的常量。
// 在 `enum` 中定义标识符等价于定义 constexpr 常量，
// 这些标识符不需要前缀，可以直接引用。
// 因此 `enum` 定义会污染命名空间。
enum ColorEnum : unsigned char {
    COLOR_RED = 31,
    COLOR_GREEN,
    COLOR_YELLOW,
    COLOR_BLUE,
};

// 有作用域枚举型是 C++ 引入的类型安全枚举。
// 其内部标识符需要带前缀引用，如 `Color::Red`。
// 作用域枚举型可以避免命名空间污染，并提供类型安全保证。
enum class Color : int {
    Red = COLOR_RED,
    Green,
    Yellow,
    Blue,
};

ColorEnum convert_by_pun(Color c) {
    // READ: <https://zh.cppreference.com/w/cpp/language/union>
    // `union` 表示在同一内存位置存储的不同类型的值。
    // 其常见用法是实现类型双关转换，即将一种类型的值转换为另一种无关类型的值。
    // 但这种写法实际上仅在 C 语言良定义，在 C++ 中是未定义行为。
    // 这是比较少见的 C++ 不与 C 保持兼容的特性。
    // READ: 类型双关 <https://tttapa.github.io/Pages/Programming/Cpp/Practices/type-punning.html>
    union TypePun {
        ColorEnum e;
        Color c;
    };

    TypePun pun;
    // TODO: 补全类型双关转换
    pun.c = c;  // 将 Color 值存入联合体

    return pun.e;
}

int main(int argc, char **argv) {
    ASSERT(convert_by_pun(Color::Red) == COLOR_RED, "Type punning conversion");
    ASSERT(convert_by_pun(Color::Green) == COLOR_GREEN, "Type punning conversion");
    ASSERT(convert_by_pun(Color::Yellow) == COLOR_YELLOW, "Type punning conversion");
    ASSERT(convert_by_pun(Color::Blue) == COLOR_BLUE, "Type punning conversion");
    return 0;
}
/*
看不懂


好的，我来详细讲解C++中的枚举类型。枚举是C++中用来定义命名常量集合的重要特性。
1. 无作用域枚举 (C风格枚举)
这是C语言继承而来的枚举类型，使用enum关键字定义：
// 基本语法
enum 枚举名 {
    标识符1 = 值1,
    标识符2 = 值2,
    // ...
};

// 示例
enum ColorEnum : unsigned char {
    COLOR_RED = 31,    // 红色，值为31
    COLOR_GREEN,       // 绿色，值为32（自动递增）
    COLOR_YELLOW,      // 黄色，值为33
    COLOR_BLUE,        // 蓝色，值为34
};

特点：

自动递增：如果没有显式指定值，后续标识符的值会自动递增
命名空间污染：所有标识符都在外层作用域可见
使用方式：直接使用标识符名，如 COLOR_RED
底层类型：可以指定底层类型（如: unsigned char）

2. 有作用域枚举 (C++11引入)
为了解决命名空间污染问题，C++11引入了有作用域枚举：
// 基本语法
enum class 枚举名 : 底层类型 {
    标识符1 = 值1,
    标识符2 = 值2,
    // ...
};

// 示例
enum class Color : int {
    Red = 31,      // 必须使用 Color::Red 访问
    Green,         // 值为32
    Yellow,        // 值为33
    Blue,          // 值为34
};

特点：

作用域限定：标识符必须通过枚举名访问，如 Color::Red
类型安全：不能隐式转换为整数，需要显式转换
避免污染：不会污染外层命名空间
必须显式指定：使用时要带枚举名前缀

3. 枚举的使用示例
#include <iostream>

// 无作用域枚举
enum Weekday {
    MONDAY = 1,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
};

// 有作用域枚举
enum class Status : int {
    OK = 0,
    ERROR = 1,
    PENDING = 2
};

int main() {
    // 使用无作用域枚举
    Weekday today = MONDAY;  // 直接使用标识符
    std::cout << "Today is: " << today << std::endl;  // 输出: 1
    
    // 使用有作用域枚举
    Status current = Status::OK;
    // std::cout << current << std::endl;  // 错误！不能隐式转换为int
    
    // 需要显式转换
    std::cout << "Status: " << static_cast<int>(current) << std::endl;
    
    return 0;
}

4. 枚举的优势

可读性：使用有意义的名称代替魔术数字
类型安全：有作用域枚举提供更好的类型检查
可维护性：集中管理相关常量
调试友好：调试时显示名称而不是数字

5. 枚举的进阶用法
指定底层类型
enum class Byte : unsigned char {
    ZERO = 0,
    MAX = 255
};

枚举作为函数参数
void setColor(Color color) {
    switch(color) {
        case Color::Red:
            // 处理红色
            break;
        case Color::Green:
            // 处理绿色
            break;
        // ...
    }
}

枚举与位运算
enum class Permissions : unsigned int {
    READ = 1 << 0,    // 1
    WRITE = 1 << 1,   // 2
    EXECUTE = 1 << 2  // 4
};

// 使用
Permissions userPerms = static_cast<Permissions>(
    static_cast<unsigned int>(Permissions::READ) | 
    static_cast<unsigned int>(Permissions::WRITE)
);

6. 最佳实践

优先使用有作用域枚举（enum class）
为枚举指定明确的底层类型
避免使用无作用域枚举，除非需要与C代码交互
使用有意义的命名前缀（如COLOR_、STATUS_等）

7. 注意事项

有作用域枚举不能隐式转换为整数
无作用域枚举会污染命名空间
枚举的底层类型影响其内存占用和取值范围

希望这个详细的讲解能帮助你理解C++中的枚举类型！
*/